package com.wongsir.tiny_spring_reproduce.beans.factory;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.wongsir.tiny_spring_reproduce.beans.BeanDefinition;
import com.wongsir.tiny_spring_reproduce.beans.BeanPostProcessor;

/**
 * 基于BeanFactory工厂接口的实现与扩展<br/>
 * 生产bean（根据bean的名称获取bean）
 * @author wongsir
 * @date 2018年8月27日
 */
public abstract class AbstractBeanFactory implements BeanFactory {

	private Map<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
	
	private final List<String> beanDefinitionNames = new ArrayList<>();
	
	private List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();
	
	@Override
	public Object getBean(String beanName) throws Exception {
		BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
		if(beanDefinition == null) {
			throw new IllegalArgumentException("No bean named " + beanName + " is defined");
		}
		Object bean = beanDefinition.getBean();
		if(bean == null) {
			//创建bean
			bean = doCreateBean(beanDefinition);
			//执行用户扩展的bean后置处理器，如果有则执行
			bean = initializeBean(bean,beanName);
		}
		return bean;
	}
	
	/**
	 * 注册BeanDefinition（以便后续获取bean的时候生成该bean）
	 * @param beanName
	 * @param beanDefinition
	 * @throws Exception
	 */
	public void registerBeanDefinition(String beanName,BeanDefinition beanDefinition) throws Exception {
		beanDefinitionMap.put(beanName, beanDefinition);
		beanDefinitionNames.add(beanName);
	}

	/**
	 *  初始化bean的后置处理器
	 * @param bean
	 * @param beanName
	 * @return
	 */
	private Object initializeBean(Object bean, String beanName) throws Exception{
		
		for(BeanPostProcessor beanPostProcessor : beanPostProcessors) {
			bean = beanPostProcessor.postProcessBeforeInitialization(bean, beanName);
		}
		
		for(BeanPostProcessor beanPostProcessor :beanPostProcessors) {
			bean = beanPostProcessor.postProcessAfterInitialization(bean, beanName);
		}
		return bean;
	}

	/**
	 * 执行创建bean的逻辑处理
	 * @param beanDefinition
	 * @return
	 * @throws Exception
	 */
	private Object doCreateBean(BeanDefinition beanDefinition) throws Exception{
		Object bean = createBeanInstance(beanDefinition);
		beanDefinition.setBean(bean);
		applyPropertyValues(bean,beanDefinition);
		return bean;
	}

	private void applyPropertyValues(Object bean, BeanDefinition beanDefinition) throws Exception{
		
	}

	private Object createBeanInstance(BeanDefinition beanDefinition) throws Exception{
		return beanDefinition.getBeanClass().newInstance();
	}

}
